;;; packages.el --- Spell Checking Layer packages File for Spacemacs  -*- lexical-binding: nil; -*-
;;
;; Copyright (c) 2012-2025 Sylvain Benner & Contributors
;;
;; Author: Sylvain Benner <sylvain.benner@gmail.com>
;; URL: https://github.com/syl20bnr/spacemacs
;;
;; This file is not part of GNU Emacs.
;;
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.

(defconst spell-checking-packages
  '(
    (auto-dictionary :toggle spell-checking-enable-auto-dictionary)
    flyspell
    flyspell-correct
    (flyspell-correct-ivy :toggle (configuration-layer/layer-used-p 'ivy))
    (flyspell-correct-helm :toggle (configuration-layer/layer-used-p 'helm))
    (flyspell-correct-popup :toggle (and (not (configuration-layer/layer-used-p 'ivy))
                                         (not (configuration-layer/layer-used-p 'helm))))
    (flyspell-popup :toggle enable-flyspell-auto-completion)))

(defun spell-checking/init-auto-dictionary ()
  (use-package auto-dictionary
    :defer t
    :init
    (add-hook 'flyspell-mode-hook 'auto-dictionary-mode)
    ;; Select the buffer local dictionary if it was set, otherwise
    ;; auto-dictionary will replace it with a guessed one at each activation.
    ;; https://github.com/nschum/auto-dictionary-mode/issues/5
    (defun spacemacs//adict-set-local-dictionary ()
      "Set the local dictionary if not nil."
      (when (and (fboundp 'adict-change-dictionary)
                 ispell-local-dictionary)
        (adict-change-dictionary ispell-local-dictionary)))
    (add-hook 'auto-dictionary-mode-hook
              'spacemacs//adict-set-local-dictionary 'append)))

(defun spell-checking/init-flyspell ()
  (use-package flyspell
    :defer t
    :commands (spell-checking/change-dictionary)
    :init
    (spacemacs|define-transient-state spell-checking
      :title "Spell Checking Transient State"
      :doc "
Spell Commands^^            Add To Dictionary^^               Other
--------------^^----------  -----------------^^-------------  -----^^---------------------------
[_b_] check whole buffer    [_B_] add word to dict (buffer)   [_t_] toggle spell check
[_r_] check region          [_G_] add word to dict (global)   [_q_] exit
[_d_] change dictionary     [_S_] add word to dict (session)  [_Q_] exit and disable spell check
[_n_] next spell error
[_c_] correct before point
[_s_] correct at point"
      :on-enter (flyspell-mode)
      :bindings
      ("B" spacemacs/add-word-to-dict-buffer)
      ("b" flyspell-buffer)
      ("r" flyspell-region)
      ("d" spell-checking/change-dictionary)
      ("G" spacemacs/add-word-to-dict-global)
      ("n" flyspell-goto-next-error)
      ("c" flyspell-correct-wrapper)
      ("Q" flyspell-mode :exit t)
      ("q" nil :exit t)
      ("S" spacemacs/add-word-to-dict-session)
      ("s" flyspell-correct-at-point)
      ("t" spacemacs/toggle-spelling-checking))

    (spacemacs/set-leader-keys "S." 'spacemacs/spell-checking-transient-state/body)
    (spell-checking/add-flyspell-hook 'text-mode-hook)
    (when spell-checking-enable-by-default
      (add-hook 'prog-mode-hook 'flyspell-prog-mode))

    (spacemacs|add-toggle spelling-checking
      :status flyspell-mode
      :on (if (derived-mode-p 'prog-mode)
              (flyspell-prog-mode)
            (flyspell-mode))
      :off (progn
             (flyspell-mode-off)
             ;; Also disable auto-dictionary when disabling spell-checking.
             (when (fboundp 'auto-dictionary-mode) (auto-dictionary-mode -1)))
      :documentation "Enable automatic spell checking."
      :evil-leader "tS")

    (spacemacs/declare-prefix
      "S"  "spelling"
      "Sa" "add word to dict")
    (spacemacs/set-leader-keys
      "Sab" 'spacemacs/add-word-to-dict-buffer
      "Sag" 'spacemacs/add-word-to-dict-global
      "Sas" 'spacemacs/add-word-to-dict-session
      "Sb" 'flyspell-buffer
      "Sr" 'flyspell-region
      "Sd" 'spell-checking/change-dictionary
      "Sn" 'flyspell-goto-next-error
      "Ss" 'flyspell-correct-at-point)
    :config (spacemacs|diminish flyspell-mode " Ⓢ" " S")))

(defun spell-checking/init-flyspell-correct ()
  (use-package flyspell-correct
    :commands (flyspell-correct-at-point
               flyspell-correct-wrapper)
    :init
    (spacemacs/set-leader-keys "Sc" #'flyspell-correct-wrapper)))

(defun spell-checking/init-flyspell-correct-ivy ()
  (use-package flyspell-correct-ivy
    :commands (flyspell-correct-ivy)
    :init
    (setq flyspell-correct-interface #'flyspell-correct-ivy)))

(defun spell-checking/init-flyspell-correct-helm ()
  (use-package flyspell-correct-helm
    :commands (flyspell-correct-helm)
    :init
    (setq flyspell-correct-interface #'flyspell-correct-helm)))

(defun spell-checking/init-flyspell-correct-popup ()
  (use-package flyspell-correct-popup
    :commands (flyspell-correct-popup)
    :init
    (setq flyspell-correct-interface #'flyspell-correct-popup)))

(defun spell-checking/init-flyspell-popup ()
  (use-package flyspell-popup
    :defer t
    :init
    (setq flyspell-popup-correct-delay 0.8)
    (add-hook 'flyspell-mode-hook 'flyspell-popup-auto-correct-mode)))
